package com.cta.service.core.impl;

import javax.jms.JMSException;

import org.apache.commons.lang.StringUtils;
import org.joda.money.BigMoney;
import org.joda.time.DateTime;
import org.joda.time.LocalTime;
import org.joda.time.Period;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.cta.entity.CallReport;
import com.cta.entity.Profile;
import com.cta.exception.InsertDataFail;
import com.cta.exception.MissingConfigException;
import com.cta.jms.TransferObject;
import com.cta.utils.CodeLookupUtils;
import com.cta.view.model.CallData;
import com.cta.view.model.ConfigModel;
import com.cta.view.model.ProfileModel;

@Service("recoveryCdr")
@Transactional(readOnly = true)
public class RecoveryProcessorImpl extends ProcessorImpl {

	private static final Logger log = LoggerFactory.getLogger(RecoveryProcessorImpl.class);

	@Override
	public CallReport process(CallData data) {
		ConfigModel configModel = lookup(data);
		if (configModel != null) {
			log.info(String.format("Found area code: %s - %s", configModel.getAreaCode(), configModel.getAreaName()));
			String error = validate(data, configModel);
			if (error == null) {
				try {
					BigMoney price = caculate(data, configModel);
					// convert to call report;
					if (price != null) {
						return createCallReport(data, price, configModel);
					}
				} catch (MissingConfigException e) {
					log.error(e.getMessage());

				} catch (InsertDataFail e) {
					log.error(">>>>>>>>>>>>>>>>>>>>>>> Can not save data to database, please check", e);
				} catch (Exception e) {
					log.error(
							String.format(" >>>>>>>>>>>>>>>>>>>>>>> Calculate fail for area code: %s - %s",
									configModel.getAreaCode(), configModel.getAreaName()), e);
				}
			} else {
				log.error(String.format(" >>>>>>>>>>>>>>>>>>>>>>> Validate fail for dial number: %s - reason: %s",
						data.getDialedNumber(), error));
			}
		} else {
			log.error(String.format(">>>>>>>>>>>>>>>>>>>>>>> Can not found area code for dial number: %s",
					data.getDialedNumber()));
		}
		return null;
	}
	

	public CallReport onMessage(TransferObject msg) throws JMSException {
		try {
			String data = msg.getRawData();
			// get config
			ProfileModel profileConfig = CodeLookupUtils.getProfile(msg.getPbxId());
			if (profileConfig != null && StringUtils.isNotEmpty(data)) {
				if (profileConfig.getLength() == data.trim().length()) {
					data = data.trim();
					int i = 0, e = 0;
					CallData callData = new CallData(data);
					for (Profile profile : profileConfig.getMapProfiles()) {
						e = i + profile.getNumOfBytes();
						if (data.length() >= e) {
							String val = data.substring(i, e);
							// ignore space character
							i = e + profile.getSpace();
							if (ProfileModel.isStartDate(profile)) {
								DateTime dateTime = new DateTime(profileConfig.getDateFormat().parse(val.trim())
										.getTime());
								callData.addData(profile, dateTime);
							} else if (ProfileModel.isStartTime(profile)) {
								LocalTime localTime = LocalTime.fromDateFields(profileConfig.getTimeFormat().parse(
										val.trim()));
								callData.addData(profile, localTime);
							} else if (ProfileModel.isDuration(profile)) {
								LocalTime localTime = LocalTime.fromDateFields(profileConfig.getDurationFormat().parse(
										val.trim()));
								Period p = new Period(localTime.getHourOfDay(), localTime.getMinuteOfHour(),
										localTime.getSecondOfMinute(), 0);
								callData.addData(profile, p);
							} else {
								// trim and may be cut just number value
								callData.addData(profile, val.trim());
							}
						}
					}
					callData.setPbxId(msg.getPbxId());
					return process(callData);
				} else {
					String errorText = String
							.format("Data is not valid( not match length)-> real data length (%s), config length (%s) for raw data: %s",
									data.length(), profileConfig.getLength(), data);
					log.error(errorText);
				}
			} else if (profileConfig == null) {
				log.error(String.format("can not get profile config for this pbx %s", msg.getPbxId()));
			} else {
				log.error(String.format("data invalid %s", data));
			}

		} catch (Exception e) {
			log.error("Error", e);
		}
		return null;
	}

}
